/*
 * channelmonitor.c
 *
 * Created: 12/10/2012 12:17:26 PM
 *  Author: duerk@msoe.edu <Kevin Duer>
 *			zimmermane@msoe.edu <Evan Zimmerman>
 *			woottons@msoe.edu <Scott Wootton>
 *			
 * Purpose: to monitor the channel for 2400 bits/second
 */ 


#include <avr/io.h>
#include <stdbool.h>		//for boolean
#include "channelMonitor.h" //defines functions
#include <avr/io.h>			//i/o register definitions
#include <avr/interrupt.h>	//interrupt definitions
#include <stdint.h>			//for uint types
#include <stdlib.h>			//for rand
#include <stdbool.h>		//for boolean
#include <stdio.h>
#include <util/delay.h>
//#include "transmission.h"
//#include "reciever.h"

volatile bool previousCol;
volatile bool previousMonitor; //True = high; False = low;

static volatile char receiveBuffer[BUFFER_LENGTH] = {0};
static volatile uint8_t receiveBufferCount;
static volatile uint8_t receiveCount = 0;
static volatile uint8_t receiveLength = 0;
static volatile bool first = true;
static volatile bool receiving;
static volatile bool display;
static volatile bool wasreceiving;

volatile uint8_t count = 16;

#define BUFFER_LENGTH 40

volatile uint16_t networkBuffer[BUFFER_LENGTH] = {0};
volatile uint8_t bufferCount = 0;
volatile uint8_t bufferLength = 0;

/* initChannelMonitor()
 * Purpose: To setup the channel monitor
 * Parameters: None
 * Returns: None
 */
void initChannelMonitor(){
	idle = false;						//Set all of the signals to be false
	collision = false;
	busy = false;
	transmitting = false;
	previousCol = false;
	
	MCUCR |= (0<<ISC11)|(1<<ISC10);		//Begin listening for a (0=ISC11)&(1=ISC10) => Any change
	GICR |= (1<<INT1); 					//Enable INT1 interrupts
	previousMonitor = false;				//Look for a falling edge
	

	TCCR1A = 0x00;						//Set Timer0 to CTC Mode
	TCCR1B = (1<<WGM12)|T1_PRESCALER_CODE; 				//Sets up the Timer1 Prescaler, without it running
//	TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10)); //Prevents the Timer1 from counting
	TIMSK |= (1<<OCIE1A);				//Enable Timer1 OCR1A Interrupts
	OCR1A = T1_OVERFLOW;				//Sets up the overflow value
	DDRD |= (0<<PD6)|(0<<PD3);			//Sets the ICP1 to be an input
	//TCCR1B |= T1_PRESCALER_CODE; //Start Timer1 Counting
	//sei();								//enable global interrupts
}


/* TIMER1_COMPA_vect
 * Purpose: 
 * Parameters:
 * Returns:
 */
ISR(TIMER1_COMPA_vect){
	uint8_t val = (PIND>>PD6)&0x01;		//Shift PIND over to place ICP1 all the way to the right
										//and strip all of the other bits off
	TCNT1 = 0;//Reset TCNT1
	if(val==0x01)
	{
		//ICP1 = 1 (idle state)
		idle = true;					//Idle state
		collision = false;
		busy = false;
		if(previousCol)
		{
			handleIdle();
			previousCol = false;
		}			
	} else {
		//ICP1 = 0 (Collision detected)
		idle = false;
		collision = true;				//Collision state
		busy = false;
		if(transmitting)
		{
			handleCollision();
			previousCol = true;
		} else if(receiving)
		{
			handleReceiveCollision();
		}
	}
}


void initReceive()
{
	DDRD &= ~((1<<PD6) | (1<<PD3));//Sets the ICP1 to be an input
	receiveCount = 0;
	receiveLength = 0;
	receiveBufferCount = 0;
	first = true;
	display = false;
	
	wasreceiving = false;
	
	TIMSK |= (1<<OCIE0);				//enable timer0 interrupt
	
	TCCR0 = (1<<WGM01); //CTC MODE
	OCR0 = 26; //104us, 1/4 bit interval
	receiving = false; //Not currently receiving
}

void displayBuffer()
{
	int i = 0;
	for(i = 0; i < receiveBufferCount; ++i)
	{
		char c = (receiveBuffer[i]);
		if(i == 2){ // print the source address
			printf("s %u : ", c);
		}
		else if(i == 3){ // print the destination address
			printf("d %u : ", c);
		}
		else if(i > 6){ 		
			printf("%c", c); // print the message
		}		
	}
	printf("\n");
}

void handleReceiveCollision()
{
	TCCR0 &= ~((1<<CS01)|(1<<CS00)); // set first, disable timer
	first = true;
	receiveBufferCount = 0; //reset the buffer count
	receiveCount = 0;
}

ISR(TIMER0_COMP_vect){
	TCNT0 = 0;
	if(first){
		first = false;
		OCR0 = 104; // 416us next match
	}
	uint8_t data = PIND;
	data = (data>>PD6)&(0x01);
	receiveBuffer[receiveBufferCount] = (receiveBuffer[receiveBufferCount]<<1)|data;
	receiveCount++;
	
	//Receive stuff
	if(receiveCount >= 8)
	{
		
		receiveCount = 0;
		
		if(receiveBufferCount > 6){ // do not convert header bytes
			char c = (receiveBuffer[receiveBufferCount])&(0x7F); // if in data section, set upper bit to 0
			receiveBuffer[receiveBufferCount] = c;
		}		
		
		receiveBufferCount++;
		//display = true;
		if((receiveBufferCount >= (receiveBuffer[4]+7)) || (receiveBufferCount == BUFFER_LENGTH)/*(c == '\n') || (c == '\r')*/)
		{
			cli();
			TCCR0 &= ~((1<<CS01)|(1<<CS00)); // set first, disable timer
			displayBuffer();
			receiveBufferCount = 0; //reset the buffer count
			uint8_t i;
			for(i=0; i<BUFFER_LENGTH; i++){
				receiveBuffer[i] = 0x00;
			}
			_delay_ms(500);
			GIFR = 0xFF; // clear the external interrupt flags
			first = true;
			wasreceiving = true;
			receiving = false; //done
			sei();
		}
	}
}

/* INT1_vect
 * Purpose: 
 * Parameters:
 * Returns:
 */
ISR(INT1_vect)
{
	//Get the current INT1 level
	volatile bool currentMonitor = (PIND>>PD6)&0x01;
	//Check for an edge transition
//	if(currentMonitor != previousMonitor)
//	{
//		//Edge transition occurred, so set the current state
//		previousMonitor = currentMonitor;
		TCNT1 = 0; //Reset TCNT1 because edge transition occurred
		if(currentMonitor)
		{
			//Rising edge, so start the timer when receiving
			if(!transmitting)
			{
				
				if(first)
				{
					//if(wasreceiving){
					//	wasreceiving = false;
					//}
					//else{
						TCNT0 = 0;
						OCR0 = 26; // 104us, 1/4 bit interval					
						TCCR0 |= (1<<CS01)|(1<<CS00); // clk/64 start timer
						
						receiving = true; //start
					//}					
				}
			}
//		}
		//Current state is busy.  Idle and Collision states will be set in the timer
		// overflow
		busy = true;
		idle = false;
		collision = false;
	}
}

void addNetworkChar(volatile char* c)
{
	while(transmitting); //Wait until the transmission is complete
	transmitting = true;
	uint8_t i;
	uint16_t temp;
	
	temp = encodeChar(0xFA);
	networkBuffer[0] = temp; // header start 25 26
	temp = encodeChar(0x00);
	networkBuffer[1] = temp; // version number
	temp = encodeChar(source);
	networkBuffer[2] = temp; // source address
	temp = encodeChar(destination);
	networkBuffer[3] = temp; // destination address
	temp = encodeChar(0x00);
	networkBuffer[5] = temp; // CRC Usage (none)
	temp = encodeChar(0xFF);
	networkBuffer[6] = temp; // Header CRC (not used)
	
	for(i = 0; (i < BUFFER_LENGTH) && (c[i] != '\n') && (c[i] != '\0'); i++)
	{
		char cur = c[i];
		cur |= (1<<7);
		temp = encodeChar(cur);
		networkBuffer[i+7] = temp;
	}
	count = 0;
	bufferLength = i+7;
	
	temp = encodeChar(i);
	networkBuffer[4] = temp; // message length
	
	networkBuffer[i+7] = 0;
	bufferCount = 0;
	while((!idle) || (busy) || (collision));
	TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on, which causes interrupts
}

void handleCollision()
{
	bufferCount = 0;
	count = 0;
	TCCR2 &= (~((1<<CS22)|(1<<CS21)|(1<<CS20))); //Turns the timer off
	PORTD |= (1<<OC2); //Output a solid 1
}

void handleIdle()
{
	/*if(transmitting){
		bufferCount = 0;
		count = 0;
		_delay_ms((rand()%128)+1);
		if((idle) && (!busy) && (!collision))
		{
			TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on, which causes interrupts
		} else {
			handleIdle();
		}
	}	*/
}

/* initTX
 * 
 * Purpose: To initialize the the transmit functionality
 * Params: none
 * Returns: none
 */
void initTx(){
	DDRD |= (1<<PD7); //Set PD7 to be an output
	PORTD |= (1<<PD7);
	TCCR2 = (1<<WGM21)|(0<<WGM20); //CTC Mode without a prescaler
	//TCCR2 &= (~((1<<CS22)|(1<<CS21)|(1<<CS20))); //Turns the timer off
	//TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on
	OCR2 = BIT_OVERFLOW;
	TIMSK |= (1<<OCIE2); //Enable Timer2 Output Compare
	TCNT2 = 0; //Reset the timer count
	count = 0; //Set the count to the max
	//sei();
}

uint16_t encodeChar(char c)
{
	uint16_t ret = 0x0000;
	char toSend = c;//|(1<<7);
	int i;
	for(i = 0; i < 8; ++i)
	{
		uint16_t encode;
		if(((toSend>>i)&(0x01)) == 1)
		{
			//1 transmitted
			encode = 0x0002;
		} else {
			//0 Transmitted
			encode = 0x0001;
		}
		//Shift the data by 1 and put the new bit at the end
		ret = (ret<<2) | encode;
	}
	return ret;
}

void startTransmission()
{
	TCCR2 |= (0<<CS22)|(1<<CS21)|(1<<CS20); //Turns the timer on, which causes interrupts
}

/* TIMER2_COMP_vect
 * 
 * Purpose: Used to transmit the data
 * Params: none
 * Returns: none
 */
ISR(TIMER2_COMP_vect){
	//Reset the timer
	TCNT2 = 0;
	if(bufferCount < bufferLength)
	{
		//Send stuff
		uint16_t data = networkBuffer[bufferCount];
		PORTD = (((data>>count)&(0x0001))<<OC2); //Output the current bit and move it
		count++; //bit sent
		if(count >= 16)
		{
			count = 0;
			bufferCount++;
		}
	} else {
		//no more
		TCCR2 &= (~((1<<CS22)|(1<<CS21)|(1<<CS20))); //Turns the timer off
		PORTD |= (1<<OC2); //Output a solid 1
		//Reached the end so transmit a solid 1 and turn the timer off
		TCNT2 = 0; //Reset the count
		transmitting = false;
		bufferCount = 0;
	}
}


/*
 * Milestone5.c
 *
 * Created: 2/5/2013 8:59:46 AM
 *  Author: Evan
 */ 


#include <stdbool.h>		//for boolean
#include <avr/io.h>					//i/o register definitions
#include <stdio.h>
#include <avr/interrupt.h>			//interrupt definitions
#include <stdint.h>					//for uint types
#include <stdlib.h>			//for rand
//#include "reciever.h"
#include "channelmonitor.h" //defines functions
//#include "transmission.h"			//header file for this class
#include "uart.h"


#define F_CPU 16000000
#include <util/delay.h>

FILE uart_str = FDEV_SETUP_STREAM(uart_putc,uart_getc,_FDEV_SETUP_RW);

/* int main()
 * Purpose: THe main function of the program
 * Parameters: None
 * Returns: None
 */
int main(){
	_delay_ms(1000);
	initTx();
	initReceive();
	char text[MAX_BUFFER_SIZE];
	char text2[MAX_BUFFER_SIZE];
	char addr[10];
	initChannelMonitor();
	//SET BAUD RATE = 9600
	uart_init(103);
	DDRB = 0xFF;
	stdout = stdin = &uart_str;
	
	_delay_ms(100);
	printf("Welcome\n");
	_delay_ms(100);
	printf("Enter Source Address\n");
	fgets(addr,10,stdin);
	sscanf(addr,"%d", &source);
	
	sei();	
	
	while(1){
		if(idle){					//check idle
			PORTB |= (1<<1);
			if(UCSRA & (1<<UDRE)){
				fgets(text,MAX_BUFFER_SIZE, stdin);
				sscanf(text,"%d %[^\n]", &destination, text2);
				//printf("%s", text);
				addNetworkChar(text2);
			}
		}
		else{							//otherwise not idle
			PORTB &= ~(1<<1);
		}
		if(busy){					//check busy
			PORTB |= (1<<2);
		}
		else{							//otherwise not busy	
			PORTB &= ~(1<<2);
		}
		if(collision){				//check collision
			PORTB |= (1<<3);
		}	
		else{							//otherwise no collision
			PORTB &= ~(1<<3);
		}
	}
	return 0;	
}
